#include <GLTools.h>            // OpenGL toolkit
#include <assert.h>
#include <iostream>
#include <string>

#ifdef __APPLE__
#include <glut/glut.h>          // OS X version of GLUT
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>            // Windows FreeGlut equivalent
#endif

using namespace std;
GLuint shader;

///////////////////////////////////////////////////////////////////////////////
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.

void ChangeSize(int w, int h) {

    glMatrixMode (GL_PROJECTION);    /* prepare for and then */ 
    glLoadIdentity ();               /* define the projection */
        gluPerspective( 60.0, w/h, 1.0, 200.0 ); 

    glMatrixMode (GL_MODELVIEW);  /* back to modelview matrix */
        glLoadIdentity ();  
    glViewport (0, 0, w, h);      /* define the viewport */
}


///////////////////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.

void SetupRC() {
  
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    shader = gltLoadShaderPairWithAttributes("shader.vp", "shader.fp",
            2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_COLOR, "vColor");
    fprintf(stdout, "GLT_ATTRIBUTE_VERTEX : %d\nGLT_ATTRIBUTE_COLOR : %d \n",
            GLT_ATTRIBUTE_VERTEX, GLT_ATTRIBUTE_COLOR);

    glEnable(GL_DEPTH_TEST);
}

void CheckForErrors()
{
        int er = glGetError();

        if (er == GL_INVALID_ENUM)
        {
                cout << "Error: INVALID_ENUM" << endl;
        }
        else
        if (er == GL_INVALID_VALUE)
        {
                cout << "Error: GL_INVALID_VALUE" << endl;
        }
        else
        if (er == GL_INVALID_OPERATION)
        {
                cout << "Error: GL_INVALID_OPERATION" << endl;
        }
        else
        if (er == GL_STACK_OVERFLOW)
        {
                cout << "Error: GL_STACK_OVERFLOW" << endl;
        }
        else
        if (er == GL_STACK_UNDERFLOW)
        {
                cout << "Error: GL_STACK_UNDERFLOW" << endl;
        }
        else
        if (er == GL_OUT_OF_MEMORY)
        {
                cout << "Error: GL_OUT_OF_MEMORY" << endl;
        }
        else
        if (er == GL_TABLE_TOO_LARGE)
        {
                cout << "Error: GL_TABLE_TOO_LARGE" << endl;
        }
}

void DrawPiramid()
{
        // podstawwa
        glBegin(GL_QUADS);
                glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 0.0, 0.0);
                //glColor3f(1.0f, 0.0f, 0.0f);
                glVertex3f(-0.5f, 0.0f, 0.5f);
                glVertex3f(0.5f, 0.0f, 0.5f);
                glVertex3f(0.5f, 0.0f, -0.5f);
                glVertex3f(-0.5f, 0.0f, -0.5f);
        glEnd();

        // sciana 1
        glBegin(GL_TRIANGLES);
                glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 1.0, 0.0);
                //glColor3f(0.0f, 1.0f, 0.0f);
                glVertex3f(-0.5f, 0.0f, 0.5f);
                glVertex3f(-0.5f, 0.0f, -0.5f);
                glVertex3f(0.0f, 1.0f, 0.0f);
        glEnd();

        // sciana 2
        glBegin(GL_TRIANGLES);
                glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 0.0, 1.0);
                //glColor3f(0.0f, 1.0f, 1.0f);
                glVertex3f(0.5f, 0.0f, 0.5f);
                glVertex3f(-0.5f, 0.0f, 0.5f);
                glVertex3f(0.0f, 1.0f, 0.0f);
        glEnd();

        // sciana 3
        glBegin(GL_TRIANGLES);
                glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 1.0, 1.0);
                //glColor3f(1.0f, 1.0f, 1.0f);
                glVertex3f(0.5f, 0.0f, 0.5f);
                glVertex3f(0.5f, 0.0f, -0.5f);
                glVertex3f(0.0f, 1.0f, 0.0f);
        glEnd();

        //// sciana 4
        glBegin(GL_TRIANGLES);
                glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 0.0, 1.0);
                //glColor3f(1.0f, 1.0f, 0.0f);
                glVertex3f(0.5f, 0.0f, -0.5f);
                glVertex3f(-0.5f, 0.0f, -0.5f);
                glVertex3f(0.0f, 1.0f, 0.0f);
        glEnd();
}

void DrawGround()
{
	float gap = 2.0f;
	float lineLength = 50.0f;
	int linesNumber = 50;

	glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 1.0, 1.0);

	// horizontal
	for (int ii = 0; ii < linesNumber; ++ii )
	{
			glBegin(GL_LINES);
				glVertex3f(0.0f, 0.0f, -gap * ii);
				glVertex3f(lineLength, 0.0f, -gap * ii);
			glEnd();

			glBegin(GL_LINES);
				glVertex3f(gap * ii, 0.0f, 0.0f);
				glVertex3f(gap * ii, 0.0f, -lineLength);
			glEnd();
	}
}

void SetCameraPos()
{
	gluLookAt( 0.0f, 5.0f, 0.0f, // eye pos
				0.0f, 0.0f, -10.0f, // looking dir
				0.0f, 1.0f, 0.0);
}

///////////////////////////////////////////////////////////////////////////////
// Called to draw scene

void RenderScene(void) {
    // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    static float e = 0.0f;
        
    glUseProgram(shader);

	glPushMatrix();
		SetCameraPos();

		glPushMatrix();
			glTranslatef(-25.0f, 0.0f, 0.0f);
			DrawGround();
		glPopMatrix();

        glPushMatrix();
                glTranslatef(0.0f,0.8f, -5.0f);
                glRotatef(e += 1.0f, 0.0f, 1.0f, 0.0f);
                DrawPiramid();
        glPopMatrix();

        glPushMatrix();
                glTranslatef(0.0f,0.8f, -8.0f);
				glRotatef(90, 1.0f, 0.0f, 0.0f);
                glRotatef(e += 2.0f, 0.0f, 1.0f, 0.0f);
                DrawPiramid();
        glPopMatrix();
	glPopMatrix();


    CheckForErrors();
    glFlush();
    glutSwapBuffers();
}


///////////////////////////////////////////////////////////////////////////////
// Main entry point for GLUT based programs

int main(int argc, char* argv[]) {
  

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Triangle");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
        glutIdleFunc(RenderScene);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();
    glutMainLoop();
    return 0;
}
